/* Microsoft Reference Implementation for TPM 2.0
 *
 *  The copyright in this software is being made available under the BSD License,
 *  included below. This software may be subject to other third party and
 *  contributor rights, including patent rights, and no such rights are granted
 *  under this license.
 *
 *  Copyright (c) Microsoft Corporation
 *
 *  All rights reserved.
 *
 *  BSD License
 *
 *  Redistribution and use in source and binary forms, with or without modification,
 *  are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice, this list
 *  of conditions and the following disclaimer.
 *
 *  Redistributions in binary form must reproduce the above copyright notice, this
 *  list of conditions and the following disclaimer in the documentation and/or
 *  other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "Tpm.h"
#include "SetCommandCodeAuditStatus_fp.h"

#if CC_SetCommandCodeAuditStatus  // Conditional expansion of this file

/*(See part 3 specification)
// change the audit status of a command or to set the hash algorithm used for
// the audit digest.
/*
If a command has been selected for command audit, the command audit status will be 
updated when that command completes successfully. The digest is updated as:
commandAuditDigestnew ≔ HauditAlg(commandAuditDigestold || cpHash || rpHash) (5)
where
HauditAlg hash function using the algorithm of the audit sequence
commandAuditDigest accumulated digest
cpHash the command parameter hash
rpHash the response parameter hash
auditAlg, the hash algorithm, is set using TPM2_SetCommandCodeAuditStatus().
如果已选择命令进行命令审计，则命令审计状态将在该命令成功完成时更新。 摘要更新为：
commandAuditDigestnew ≔ HauditAlg(commandAuditDigestold || cpHash || rpHash) (5)
在哪里
HauditAlg哈希函数使用审计序列的算法
commandAuditDigest 累积摘要
cpHash 命令参数哈希
rpHash 响应参数哈希
使用 TPM2_SetCommandCodeAuditStatus() 设置哈希算法 auditAlg。

TPM2_Shutdown() cannot be audited but TPM2_Startup() can be audited. If the cpHash of the TPM2_Startup() 
is TPM_SU_STATE, that would indicate that a TPM2_Shutdown() had been successfully executed.
TPM2_SetCommandCodeAuditStatus() is always audited, except when it is used to change auditAlg.
If the TPM is in Failure mode, command audit is not functional.
无法审核 TPM2_Shutdown()，但可以审核 TPM2_Startup()。 如果 TPM2_Startup() 的 cpHash 为 TPM_SU_STATE，
则表明 TPM2_Shutdown() 已成功执行。
TPM2_SetCommandCodeAuditStatus() 始终被审计，除非它用于更改 auditAlg。
如果 TPM 处于故障模式，则命令审计不起作用。

21.2 TPM2_SetCommandCodeAuditStatus
This command may be used by the Privacy Administrator or platform to change the audit status of a command or 
to set the hash algorithm used for the audit digest, but not both at the same time.
If the auditAlg parameter is a supported hash algorithm and not the same as the current algorithm, then the TPM 
will check both setList and clearList are empty (zero length). If so, then the algorithm is changed, and the 
audit digest is cleared. If auditAlg is TPM_ALG_NULL or the same as the current algorithm, then the algorithm and
 audit digest are unchanged and the setList and clearList will be processed.
NOTE 1 Because the audit digest is cleared, the audit counter will increment the next time that an audited command 
is executed.
Use of TPM2_SetCommandCodeAuditStatus() to change the list of audited commands is an audited event. If 
TPM_CC_SetCommandCodeAuditStatus is in clearList, the fact that it is in clearList is ignored.
NOTE 2 Use of this command to change the audit hash algorithm is not audited and the digest is reset when the 
command completes. The change in the audit hash algorithm is the evidence that this command was used to change the algorithm.
隐私管理员或平台可以使用此命令来更改命令的审核状态或设置用于审核摘要的哈希算法，但不能同时使用。
如果 auditAlg 参数是受支持的散列算法并且与当前算法不同，则 TPM 将检查 setList 和 clearList 是否为空（零长度）。 如果是，则更改算法，
并清除审计摘要。 如果auditAlg为TPM_ALG_NULL或与当前算法相同，则算法和审计摘要不变，处理setList和clearList。
注 1 因为审核摘要被清除，审核计数器将在下一次执行审核命令时递增。
使用 TPM2_SetCommandCodeAuditStatus() 更改已审计命令列表是一个已审计事件。 如果 TPM_CC_SetCommandCodeAuditStatus 在 clearList 中，
则忽略它在 clearList 中的事实。
注 2 使用此命令更改审计散列算法不会被审计，并且摘要会在命令完成时重置。 审计散列算法的变化是该命令被用来改变算法的证据。

The commands in setList indicate the commands to be added to the list of audited commands and the commands in 
clearList indicate the commands that will no longer be audited. It is not an error if a command in setList is 
already audited or is not implemented. It is not an error if a command in clearList is not currently being audited 
or is not implemented.
If a command code is in both setList and clearList, then it will not be audited (that is, setList shall be processed first).
setList 中的命令表示要添加到审计命令列表中的命令，clearList 中的命令表示不再审计的命令。 如果 setList 中的命令已被审计或未执行，则不是错误。 
如果 clearList 中的命令当前未被审核或未执行，则不是错误。
如果一个命令码同时存在于setList和clearList中，则不进行审计（即先处理setList）。
*/
TPM_RC
TPM2_SetCommandCodeAuditStatus(
    SetCommandCodeAuditStatus_In    *in             // IN: input parameter list
    )
{

    // The command needs NV update.  Check if NV is available.
    // A TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE error may be returned at
    // this point
    RETURN_IF_NV_IS_NOT_AVAILABLE;

// Internal Data Update

    // Update hash algorithm
    if(in->auditAlg != TPM_ALG_NULL && in->auditAlg != gp.auditHashAlg)
    {
        // Can't change the algorithm and command list at the same time
        if(in->setList.count != 0 || in->clearList.count != 0)
            return TPM_RCS_VALUE + RC_SetCommandCodeAuditStatus_auditAlg;

        // Change the hash algorithm for audit
        gp.auditHashAlg = in->auditAlg;

        // Set the digest size to a unique value that indicates that the digest
        // algorithm has been changed. The size will be cleared to zero in the
        // command audit processing on exit.
        gr.commandAuditDigest.t.size = 1;

        // Save the change of command audit data (this sets g_updateNV so that NV
        // will be updated on exit.)
        NV_SYNC_PERSISTENT(auditHashAlg);
    }
    else
    {
        UINT32          i;
        BOOL            changed = FALSE;

        // Process set list
        for(i = 0; i < in->setList.count; i++)

            // If change is made in CommandAuditSet, set changed flag
            if(CommandAuditSet(in->setList.commandCodes[i]))
                changed = TRUE;

        // Process clear list
        for(i = 0; i < in->clearList.count; i++)
            // If change is made in CommandAuditClear, set changed flag
            if(CommandAuditClear(in->clearList.commandCodes[i]))
                changed = TRUE;

        // if change was made to command list, update NV
        if(changed)
            // this sets g_updateNV so that NV will be updated on exit.
            NV_SYNC_PERSISTENT(auditCommands);
    }

    return TPM_RC_SUCCESS;
}

#endif // CC_SetCommandCodeAuditStatus